{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "uuid": "544c8a2a-8046-461d-94a1-0257be9eef37"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>sent1</th>\n",
       "      <th>sent2</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>怎么更改花呗手机号码</td>\n",
       "      <td>我的花呗是以前的手机号码，怎么更改成现在的支付宝的号码手机号</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>也开不了花呗，就这样了？完事了</td>\n",
       "      <td>真的嘛？就是花呗付款</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>花呗冻结以后还能开通吗</td>\n",
       "      <td>我的条件可以开通花呗借款吗</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>如何得知关闭借呗</td>\n",
       "      <td>想永久关闭借呗</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>花呗扫码付钱</td>\n",
       "      <td>二维码扫描可以用花呗吗</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>花呗逾期后不能分期吗</td>\n",
       "      <td>我这个 逾期后还完了 最低还款 后 能分期吗</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>花呗分期清空</td>\n",
       "      <td>花呗分期查询</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>借呗逾期短信通知</td>\n",
       "      <td>如何购买花呗短信通知</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>借呗即将到期要还的账单还能分期吗</td>\n",
       "      <td>借呗要分期还，是吗</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>花呗为什么不能支付手机交易</td>\n",
       "      <td>花呗透支了为什么不可以继续用了</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               sent1                           sent2  label\n",
       "1         怎么更改花呗手机号码  我的花呗是以前的手机号码，怎么更改成现在的支付宝的号码手机号      1\n",
       "2    也开不了花呗，就这样了？完事了                      真的嘛？就是花呗付款      0\n",
       "3        花呗冻结以后还能开通吗                   我的条件可以开通花呗借款吗      0\n",
       "4           如何得知关闭借呗                         想永久关闭借呗      0\n",
       "5             花呗扫码付钱                     二维码扫描可以用花呗吗      0\n",
       "6         花呗逾期后不能分期吗          我这个 逾期后还完了 最低还款 后 能分期吗      0\n",
       "7             花呗分期清空                          花呗分期查询      0\n",
       "8           借呗逾期短信通知                      如何购买花呗短信通知      0\n",
       "9   借呗即将到期要还的账单还能分期吗                       借呗要分期还，是吗      0\n",
       "10     花呗为什么不能支付手机交易                 花呗透支了为什么不可以继续用了      0"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "data_df = pd.read_csv(\"atec_nlp_sim_train_all.csv\", sep=\"\\t\", header=None, \n",
    "                      encoding=\"utf-8-sig\", names=[\"sent1\", \"sent2\", \"label\"])\n",
    "data_df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "uuid": "2d322667-39c9-419b-9d28-72bc7c5c57a4"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Building prefix dict from the default dictionary ...\n",
      "Loading model from cache /tmp/jieba.cache\n",
      "Loading model cost 1.159 seconds.\n",
      "Prefix dict has been built successfully.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['怎么', '更改', '花呗', '手机号码']\n"
     ]
    }
   ],
   "source": [
    "import jieba\n",
    "\n",
    "# 添加自定义词典\n",
    "jieba.load_userdict(\"atec_dict.txt\")\n",
    "# 分词测试\n",
    "seg_words = jieba.lcut(\"怎么更改花呗手机号码\")\n",
    "print(seg_words)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "uuid": "6f2ed644-38d6-4ab5-b8f6-a6e628b1a637"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>sent1</th>\n",
       "      <th>sent2</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>[怎么, 更改, 花呗, 手机号码]</td>\n",
       "      <td>[我, 的, 花呗, 是, 以前, 的, 手机号码, ，, 怎么, 更, 改成, 现在, 的...</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>[也, 开, 不了, 花呗, ，, 就, 这样, 了, ？, 完事, 了]</td>\n",
       "      <td>[真的, 嘛, ？, 就是, 花呗, 付款]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>[花呗, 冻结, 以后, 还, 能, 开通, 吗]</td>\n",
       "      <td>[我, 的, 条件, 可以, 开通, 花呗, 借款, 吗]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>[如何, 得知, 关闭, 借呗]</td>\n",
       "      <td>[想, 永久, 关闭, 借呗]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>[花呗, 扫码, 付钱]</td>\n",
       "      <td>[二维码, 扫描, 可以, 用, 花呗, 吗]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>[花呗, 逾期, 后, 不能, 分期, 吗]</td>\n",
       "      <td>[我, 这个,  , 逾期, 后, 还, 完, 了,  , 最低, 还款,  , 后,  ,...</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>[花呗, 分期, 清空]</td>\n",
       "      <td>[花呗, 分期, 查询]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>[借呗, 逾期, 短信, 通知]</td>\n",
       "      <td>[如何, 购买, 花呗, 短信, 通知]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>[借呗, 即将, 到期, 要, 还, 的, 账单, 还, 能, 分期, 吗]</td>\n",
       "      <td>[借呗, 要, 分期, 还, ，, 是, 吗]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>[花呗, 为什么, 不能, 支付, 手机, 交易]</td>\n",
       "      <td>[花呗, 透支, 了, 为什么, 不, 可以, 继续, 用, 了]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                     sent1  \\\n",
       "1                       [怎么, 更改, 花呗, 手机号码]   \n",
       "2    [也, 开, 不了, 花呗, ，, 就, 这样, 了, ？, 完事, 了]   \n",
       "3                [花呗, 冻结, 以后, 还, 能, 开通, 吗]   \n",
       "4                         [如何, 得知, 关闭, 借呗]   \n",
       "5                             [花呗, 扫码, 付钱]   \n",
       "6                   [花呗, 逾期, 后, 不能, 分期, 吗]   \n",
       "7                             [花呗, 分期, 清空]   \n",
       "8                         [借呗, 逾期, 短信, 通知]   \n",
       "9   [借呗, 即将, 到期, 要, 还, 的, 账单, 还, 能, 分期, 吗]   \n",
       "10               [花呗, 为什么, 不能, 支付, 手机, 交易]   \n",
       "\n",
       "                                                sent2  label  \n",
       "1   [我, 的, 花呗, 是, 以前, 的, 手机号码, ，, 怎么, 更, 改成, 现在, 的...      1  \n",
       "2                              [真的, 嘛, ？, 就是, 花呗, 付款]      0  \n",
       "3                       [我, 的, 条件, 可以, 开通, 花呗, 借款, 吗]      0  \n",
       "4                                     [想, 永久, 关闭, 借呗]      0  \n",
       "5                             [二维码, 扫描, 可以, 用, 花呗, 吗]      0  \n",
       "6   [我, 这个,  , 逾期, 后, 还, 完, 了,  , 最低, 还款,  , 后,  ,...      0  \n",
       "7                                        [花呗, 分期, 查询]      0  \n",
       "8                                [如何, 购买, 花呗, 短信, 通知]      0  \n",
       "9                             [借呗, 要, 分期, 还, ，, 是, 吗]      0  \n",
       "10                  [花呗, 透支, 了, 为什么, 不, 可以, 继续, 用, 了]      0  "
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data_df[\"sent1\"] = data_df[\"sent1\"].apply(lambda x: jieba.lcut(x.strip(\"\\r\\t \").replace(\"***\",\"*\")))\n",
    "data_df[\"sent2\"] = data_df[\"sent2\"].apply(lambda x: jieba.lcut(x.strip(\"\\r\\t \").replace(\"***\",\"*\")))\n",
    "data_df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "uuid": "9a52e0af-3416-40af-9688-006e95a8d6e7"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('花呗', 141731), ('我', 61743), ('借呗', 61340), ('的', 60189), ('了', 47468), ('，', 46908), ('吗', 42196), ('还', 35076), ('怎么', 33715), ('还款', 29525)]\n"
     ]
    }
   ],
   "source": [
    "from collections import Counter\n",
    "\n",
    "c = Counter()\n",
    "sent_data = data_df[\"sent1\"].values + data_df[\"sent2\"].values\n",
    "for d in sent_data:\n",
    "    c.update(d)\n",
    "word_counts = sorted(dict(c).items(), key=lambda x: x[1], reverse=True)\n",
    "\n",
    "print(word_counts[:10])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "uuid": "82b1cf4e-d3cc-4dde-b0a1-3d267d69095c"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vocab size:  13262\n",
      "[('<PAD>', 0), ('<UNK>', 1), ('花呗', 2), ('我', 3), ('借呗', 4)]\n",
      "[(0, '<PAD>'), (1, '<UNK>'), (2, '花呗'), (3, '我'), (4, '借呗')]\n"
     ]
    }
   ],
   "source": [
    "vocab_words = [\"<PAD>\", \"<UNK>\"]\n",
    "for w, c in word_counts:\n",
    "    vocab_words.append(w)\n",
    "\n",
    "vocab2id = {w: i for i, w in enumerate(vocab_words)}\n",
    "id2vocab = {i: w for i, w in enumerate(vocab_words)}\n",
    "\n",
    "print(\"vocab size: \", len(vocab2id))\n",
    "print(list(vocab2id.items())[:5])\n",
    "print(list(id2vocab.items())[:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "uuid": "1b8afb3f-85c2-4375-a693-86c1dd43931e"
   },
   "outputs": [],
   "source": [
    "with open(\"vocab.txt\", \"w\", encoding=\"utf8\") as f:\n",
    "    for w, i in vocab2id.items():\n",
    "        f.write(w+\"\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "uuid": "e4ec585e-8b4e-41e0-aae1-ee9bac112f6f"
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>sent1</th>\n",
       "      <th>sent2</th>\n",
       "      <th>label</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>[10, 238, 2, 214]</td>\n",
       "      <td>[3, 5, 2, 17, 150, 5, 214, 7, 10, 1006, 583, 4...</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>[102, 153, 32, 2, 7, 72, 591, 6, 134, 3073, 6]</td>\n",
       "      <td>[829, 132, 134, 211, 2, 33]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>[2, 110, 181, 9, 23, 19, 8]</td>\n",
       "      <td>[3, 5, 202, 12, 19, 2, 119, 8]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>[57, 6939, 52, 4]</td>\n",
       "      <td>[68, 570, 52, 4]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>[2, 314, 584]</td>\n",
       "      <td>[212, 1031, 12, 13, 2, 8]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>[2, 38, 47, 22, 18, 8]</td>\n",
       "      <td>[3, 53, 28, 38, 47, 9, 91, 6, 28, 98, 11, 28, ...</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>[2, 18, 2285]</td>\n",
       "      <td>[2, 18, 226]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>[4, 38, 216, 402]</td>\n",
       "      <td>[57, 271, 2, 216, 402]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>[4, 2886, 196, 54, 9, 5, 63, 9, 23, 18, 8]</td>\n",
       "      <td>[4, 54, 18, 9, 7, 17, 8]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>[2, 14, 22, 34, 97, 232]</td>\n",
       "      <td>[2, 377, 6, 14, 26, 12, 327, 13, 6]</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                             sent1  \\\n",
       "1                                [10, 238, 2, 214]   \n",
       "2   [102, 153, 32, 2, 7, 72, 591, 6, 134, 3073, 6]   \n",
       "3                      [2, 110, 181, 9, 23, 19, 8]   \n",
       "4                                [57, 6939, 52, 4]   \n",
       "5                                    [2, 314, 584]   \n",
       "6                           [2, 38, 47, 22, 18, 8]   \n",
       "7                                    [2, 18, 2285]   \n",
       "8                                [4, 38, 216, 402]   \n",
       "9       [4, 2886, 196, 54, 9, 5, 63, 9, 23, 18, 8]   \n",
       "10                        [2, 14, 22, 34, 97, 232]   \n",
       "\n",
       "                                                sent2  label  \n",
       "1   [3, 5, 2, 17, 150, 5, 214, 7, 10, 1006, 583, 4...      1  \n",
       "2                         [829, 132, 134, 211, 2, 33]      0  \n",
       "3                      [3, 5, 202, 12, 19, 2, 119, 8]      0  \n",
       "4                                    [68, 570, 52, 4]      0  \n",
       "5                           [212, 1031, 12, 13, 2, 8]      0  \n",
       "6   [3, 53, 28, 38, 47, 9, 91, 6, 28, 98, 11, 28, ...      0  \n",
       "7                                        [2, 18, 226]      0  \n",
       "8                              [57, 271, 2, 216, 402]      0  \n",
       "9                            [4, 54, 18, 9, 7, 17, 8]      0  \n",
       "10                [2, 377, 6, 14, 26, 12, 327, 13, 6]      0  "
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def sent2index(vocab2id, words):\n",
    "    return [vocab2id[w] if w in vocab2id else vocab2id[\"<UNK>\"] for w in words]\n",
    "\n",
    "data_df[\"sent1\"] = data_df[\"sent1\"].apply(lambda x: sent2index(vocab2id, x))\n",
    "data_df[\"sent2\"] = data_df[\"sent2\"].apply(lambda x: sent2index(vocab2id, x))\n",
    "\n",
    "data_df.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "uuid": "7195e068-5905-480c-a846-05e172b12c1f"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.2.0\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "from tensorflow.keras import backend as K\n",
    "\n",
    "print(tf.__version__)\n",
    "\n",
    "class BaseTextCNN(keras.Model):\n",
    "    def __init__(self, filters, kernel_sizes, output_dim, name):\n",
    "        super(BaseTextCNN, self).__init__(name=name)\n",
    "        self.kernel_sizes = kernel_sizes\n",
    "        self.conv_layers = []\n",
    "        self.max_poolings = []\n",
    "        for kernel_size in kernel_sizes:\n",
    "            self.conv_layers.append(\n",
    "                keras.layers.Conv1D(filters=filters, kernel_size=kernel_size, \n",
    "                                activation='relu', padding=\"same\")\n",
    "            )\n",
    "            self.max_poolings.append(keras.layers.GlobalMaxPool1D())\n",
    "        self.concatenate = keras.layers.Concatenate()\n",
    "        self.dense = keras.layers.Dense(output_dim, activation='tanh')\n",
    "        \n",
    "    def call(self, inputs):\n",
    "        convs = []\n",
    "        for i in range(len(self.kernel_sizes)):\n",
    "            x = self.conv_layers[i](inputs)\n",
    "            x = self.max_poolings[i](x)\n",
    "            convs.append(x)\n",
    "        x = self.concatenate(convs)\n",
    "        output = self.dense(x)\n",
    "        return output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "uuid": "690b4676-85c1-4d71-8403-457e26c86f03"
   },
   "outputs": [],
   "source": [
    "max_len = 15\n",
    "vocab_size = len(vocab2id)\n",
    "embedding_size = 128\n",
    "filters = 200\n",
    "kernel_sizes = [3,4,5]\n",
    "output_dim = 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "uuid": "260b3cd0-158c-4cea-9b83-26740072f395"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Input,Embedding,Dot,Dense\n",
    "from tensorflow.keras.models import Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "uuid": "70e0a7f1-2777-4e5c-8b14-0f9caca7a87c"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Dense,Conv1D,GlobalMaxPool1D,concatenate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "uuid": "f1f0feff-991d-4d11-9060-a01ecc98f639"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Bidirectional,LSTM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "uuid": "2f213e8a-4b97-4ac5-bede-f96eef619aa1"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Attention"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "uuid": "2332da15-c47b-487d-a253-100f46f3777c"
   },
   "outputs": [],
   "source": [
    "# EMBEDDING_SIZE = 100\n",
    "hidden_size= 64\n",
    "attention_size = 50\n",
    "# hidden_size=64\n",
    "class_nums=2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "uuid": "1bc95f05-b691-4f8f-86c3-469d8a42fafa"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras.layers import Convolution1D,Activation,MaxPool1D,GRU\n",
    "from tensorflow.keras.layers import Bidirectional,LSTM,Dense,Flatten"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "uuid": "c776f7d5-185b-4591-b6c7-54688ce30e65"
   },
   "outputs": [],
   "source": [
    "input1=Input(name='sent1',shape=(max_len,))\n",
    "input2=Input(name='sent2',shape=(max_len,))\n",
    "embedding=Embedding(vocab_size,embedding_size)\n",
    "sent1_embed=embedding(input1)\n",
    "sent2_embed=embedding(input2)\n",
    "\n",
    "cnn = Convolution1D(256, 3, padding='same', strides = 1, activation='relu')(sent1_embed)\n",
    "cnn = MaxPool1D(pool_size=4)(cnn)\n",
    "cnn = Flatten()(cnn)\n",
    "cnn = Dense(256)(cnn)\n",
    "rnn = Bidirectional(GRU(256, dropout=0.2, recurrent_dropout=0.1))(sent1_embed)\n",
    "rnn = Dense(256)(rnn)\n",
    "output_sent1 = concatenate([cnn,rnn], axis=-1)\n",
    "\n",
    "\n",
    "cnn1 = Convolution1D(256, 3, padding='same', strides = 1, activation='relu')(sent2_embed)\n",
    "cnn1 = MaxPool1D(pool_size=4)(cnn1)\n",
    "cnn1 = Flatten()(cnn1)\n",
    "cnn1 = Dense(256)(cnn1)\n",
    "rnn1= Bidirectional(GRU(256, dropout=0.2, recurrent_dropout=0.1))(sent1_embed)\n",
    "rnn1 = Dense(256)(rnn1)\n",
    "output_sent2 = concatenate([cnn1,rnn1], axis=-1)\n",
    "\n",
    "cosine_output=Dot(axes=[1,1],normalize=True)([output_sent1,output_sent2])\n",
    "outputs=Dense(1,activation='linear',name=\"output\")(cosine_output)\n",
    "model=Model(inputs=[input1,input2],outputs=outputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "uuid": "dc9edcbd-93b6-4b94-bd2d-13e933dc9d0c"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model\"\n",
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "sent1 (InputLayer)              [(None, 15)]         0                                            \n",
      "__________________________________________________________________________________________________\n",
      "sent2 (InputLayer)              [(None, 15)]         0                                            \n",
      "__________________________________________________________________________________________________\n",
      "embedding_1 (Embedding)         (None, 15, 128)      1697536     sent1[0][0]                      \n",
      "                                                                 sent2[0][0]                      \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_1 (Conv1D)               (None, 15, 256)      98560       embedding_1[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "conv1d_2 (Conv1D)               (None, 15, 256)      98560       embedding_1[1][0]                \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling1d_1 (MaxPooling1D)  (None, 3, 256)       0           conv1d_1[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling1d_2 (MaxPooling1D)  (None, 3, 256)       0           conv1d_2[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "flatten (Flatten)               (None, 768)          0           max_pooling1d_1[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "bidirectional (Bidirectional)   (None, 512)          592896      embedding_1[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "flatten_1 (Flatten)             (None, 768)          0           max_pooling1d_2[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "bidirectional_1 (Bidirectional) (None, 512)          592896      embedding_1[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "dense (Dense)                   (None, 256)          196864      flatten[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dense_1 (Dense)                 (None, 256)          131328      bidirectional[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "dense_2 (Dense)                 (None, 256)          196864      flatten_1[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_3 (Dense)                 (None, 256)          131328      bidirectional_1[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "concatenate (Concatenate)       (None, 512)          0           dense[0][0]                      \n",
      "                                                                 dense_1[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "concatenate_1 (Concatenate)     (None, 512)          0           dense_2[0][0]                    \n",
      "                                                                 dense_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dot (Dot)                       (None, 1)            0           concatenate[0][0]                \n",
      "                                                                 concatenate_1[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "output (Dense)                  (None, 1)            2           dot[0][0]                        \n",
      "==================================================================================================\n",
      "Total params: 3,736,834\n",
      "Trainable params: 3,736,834\n",
      "Non-trainable params: 0\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "uuid": "33c24664-86ee-4c7c-85b7-02355fddfb34"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from tensorflow.keras.preprocessing.sequence import pad_sequences\n",
    "\n",
    "def batch_generator(all_data, batch_size, maxlen, shuffle=True):\n",
    "    \"\"\"\n",
    "    :param all_data : all_data整个数据集，包含输入和输出标签\n",
    "    :param batch_size: batch_size表示每个batch的大小\n",
    "    :param shuffle: 是否打乱顺序\n",
    "    :return:\n",
    "    \"\"\"\n",
    "    # 输入all_datas的每一项必须是numpy数组，保证后面能按p所示取值\n",
    "    all_data = [np.array(d) for d in all_data]\n",
    "    # 获取样本大小\n",
    "    data_size = all_data[0].shape[0]\n",
    "\n",
    "    if shuffle:\n",
    "        # 随机生成打乱的索引\n",
    "        p = np.random.permutation(data_size)\n",
    "        # 重新组织数据\n",
    "        all_data = [d[p] for d in all_data]\n",
    "        \n",
    "    batch_count = 0\n",
    "    while True:\n",
    "        # 数据一轮循环(epoch)完成，打乱一次顺序\n",
    "        if batch_count * batch_size + batch_size > data_size:\n",
    "            batch_count = 0\n",
    "            if shuffle:\n",
    "                p = np.random.permutation(data_size)\n",
    "                all_data = [d[p] for d in all_data]\n",
    "        start = batch_count * batch_size\n",
    "        end = start + batch_size\n",
    "        batch_count += 1\n",
    "        batch_data = [d[start: end] for d in all_data]\n",
    "        batch_sent1, batch_sent2, batch_label = batch_data\n",
    "        \n",
    "        batch_sent1_pad = pad_sequences(batch_sent1, maxlen=max_len, padding='post')\n",
    "        batch_sent2_pad = pad_sequences(batch_sent2, maxlen=max_len, padding='post')\n",
    "        \n",
    "        yield [batch_sent1_pad, batch_sent2_pad], batch_label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "uuid": "a0cd2d7b-ad9e-4993-9388-2c75669e3467"
   },
   "outputs": [],
   "source": [
    "sent1_datas = data_df[\"sent1\"].values.tolist()\n",
    "sent2_datas = data_df[\"sent2\"].values.tolist()\n",
    "labels = data_df[\"label\"].values.tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "uuid": "11b3aa00-1fe2-4d28-8fb1-36fb568d0845"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train data:  81981 81981 81981\n",
      "val data:  10248 10248 10248\n",
      "test data:  10248 10248 10248\n"
     ]
    }
   ],
   "source": [
    "# 划分训练 测试数据集\n",
    "count = len(labels)\n",
    "idx1, idx2 = int(count*0.8), int(count*0.9)\n",
    "sent1_train, sent2_train = sent1_datas[:idx1], sent2_datas[:idx1]\n",
    "sent1_val, sent2_val = sent1_datas[idx1:idx2], sent2_datas[idx1:idx2]\n",
    "sent1_test, sent2_test = sent1_datas[idx2:], sent2_datas[idx2:]\n",
    "\n",
    "train_labels, val_labels, test_labels = labels[:idx1], labels[idx1:idx2], labels[idx2:]\n",
    "\n",
    "print(\"train data: \", len(sent1_train), len(sent2_train), len(train_labels))\n",
    "print(\"val data: \", len(sent1_val), len(sent2_val), len(val_labels))\n",
    "print(\"test data: \", len(sent1_test), len(sent2_test), len(test_labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "uuid": "83ccd3ef-622e-4b9d-b34d-f66268d6b258"
   },
   "outputs": [],
   "source": [
    "# batch数据的生成器\n",
    "batch_size = 64\n",
    "maxlen = 15\n",
    "batch_count = int(len(train_labels) / batch_size)\n",
    "batch_gen_train = batch_generator([sent1_train, sent2_train, train_labels], batch_size, max_len)\n",
    "batch_gen_val = batch_generator([sent1_val, sent2_val, val_labels], batch_size, max_len)\n",
    "batch_gen_test = batch_generator([sent1_test, sent2_test, test_labels], batch_size, max_len)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "uuid": "ec50295e-308c-4f17-b800-e30ce1392f36"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/conda/lib/python3.6/site-packages/ipykernel_launcher.py:12: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray\n",
      "  if sys.path[0] == '':\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/2\n",
      "1280/1280 [==============================] - 148s 116ms/step - loss: 0.4760 - accuracy: 0.8126 - val_loss: 0.4369 - val_accuracy: 0.8305\n",
      "Epoch 2/2\n",
      "1280/1280 [==============================] - 146s 114ms/step - loss: 0.4480 - accuracy: 0.8126 - val_loss: 0.4371 - val_accuracy: 0.8330\n",
      "50/50 [==============================] - 1s 14ms/step - loss: 0.4166 - accuracy: 0.8400\n",
      "score: 0.4165685176849365 accuracy: 0.8399999737739563\n"
     ]
    }
   ],
   "source": [
    "epochs = 10\n",
    "\n",
    "model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "\n",
    "# 训练模型\n",
    "model.fit(batch_gen_train, \n",
    "                    verbose=1, \n",
    "                    validation_data=batch_gen_val,\n",
    "                    validation_steps=100,\n",
    "                    steps_per_epoch=batch_count, \n",
    "                    epochs=2)\n",
    "\n",
    "# 预测模型\n",
    "score, acc = model.evaluate(batch_gen_test, steps=50, \n",
    "                                      max_queue_size=10, \n",
    "                                      use_multiprocessing=False)\n",
    "print('score:', score, 'accuracy:', acc)\n",
    "\n",
    "# 保存训练好的模型\n",
    "# model.save(\"output/cnndssm_semantic_match.h5\")\n",
    "# model.save_weights(\"output/match_model_weight.h5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "uuid": "34e332c5-d175-466d-a247-5fb78a389a91"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sent1: 怎么更改花呗手机号码？\n",
      "sent2: 怎么更改成现在的支付宝的号码手机号？\n",
      "score: [0.28650525]\n"
     ]
    }
   ],
   "source": [
    "def sent2index(vocab2id, words):\n",
    "    return [vocab2id[w] if w in vocab2id else vocab2id[\"<UNK>\"] for w in words]\n",
    "\n",
    "sent1 = \"怎么更改花呗手机号码？\"\n",
    "sent2 = \"怎么更改成现在的支付宝的号码手机号？\"\n",
    "\n",
    "sent1_ids = sent2index(vocab2id, jieba.lcut(sent1))\n",
    "sent2_ids = sent2index(vocab2id, jieba.lcut(sent2))\n",
    "\n",
    "sent1_pad = pad_sequences([sent1_ids], maxlen=max_len, padding='post')\n",
    "sent2_pad = pad_sequences([sent2_ids], maxlen=max_len, padding='post')\n",
    "\n",
    "# model.load_weights(\"output/match_model_weight.h5\")\n",
    "\n",
    "preds = model.predict([sent1_pad, sent2_pad])\n",
    "\n",
    "print(\"sent1: %s\" % sent1)\n",
    "print(\"sent2: %s\" % sent2)\n",
    "print(\"score: %s\" % preds[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "uuid": "c17ad353-5e56-44a1-8265-97762fa14f95"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
